package celiasoft.itasalib.filegatherer;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.htmlcleaner.TagNode;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import android.util.Log;
import celiasoft.itasalib.filegatherer.cache.FileCache;
import celiasoft.itasalib.filegatherer.cache.filter.IFileCacheFilter;
import celiasoft.itasalib.filegatherer.cache.filter.XMLCacheFilter;

public class XMLGatherer implements IGatherer{

	private final static String TAG = "itasalib.XMLGatherer";

	private FileCache _cache;

	private boolean _cacheResult = true;

	public XMLGatherer(FileCache cache) {
		this._cache = cache;
	}

	protected String getFilePath(String url){
		return getFilePath(url,new XMLCacheFilter());
	}
	
	private String getFilePath(String url, IFileCacheFilter filter) {

		String filePath = this._cache.lookup(url);
		Log.d(TAG,"filePath == null?  " + (filePath == null) + " url = " + url);

		if (filePath == null || !_cacheResult) {
			Log.d(TAG,"cache == null? " + (_cache == null));

			try {
				URL remoteUrl = new URL(url);
				byte[] stream = FileHTTPFetcher.fetch(remoteUrl);
				Log.d(TAG,"stream == null? " + (stream == null));
				if (stream != null){ 
					if(filter == null || filter.cacheIt(stream)) {
						filePath = this._cache.cache(url, stream);
						reclaimText(filePath);		
					}
				}
			} catch (IOException ex) {
				ex.printStackTrace();
				Log.e(TAG, "Exception occurred during " + url
						+ " file fetching.");
				return null;
			}
		}

		return filePath;

	}

	public Document getDocument(String url) {
		Document doc = null;

		String filePath = getFilePath(url);

		if (filePath == null) {
			Log.d(TAG, "file fetching error");
			return null;
		}

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {

			DocumentBuilder db = dbf.newDocumentBuilder();

			InputSource is = new InputSource();
			is.setCharacterStream(new FileReader(filePath));
			doc = db.parse(is);

		} catch (ParserConfigurationException e) {
			System.out.println("XML parse error: " + e.getMessage());
			return null;
		} catch (SAXException e) {
			System.out.println("Wrong XML file structure: " + e.getMessage());
			return null;
		} catch (IOException e) {
			System.out.println("I/O exception: " + e.getMessage());
			return null;
		}

		return doc;

	}
	
	protected void reclaimText(String filePath) {
		reclaimText(filePath, "xml");
	}

	protected void reclaimText(String filePath, String fileExt) {

		boolean err = false;

		File file, temp;
		BufferedReader reader = null;
		PrintWriter writer = null;
		try {
			file = new File(filePath);
			temp = File.createTempFile("file", "." +  fileExt, file.getParentFile());
		} catch (IOException e1) {
			e1.printStackTrace();
			return;
		}

		try {

			reader = new BufferedReader(new InputStreamReader(
					new FileInputStream(file)));
			writer = new PrintWriter(new OutputStreamWriter(
					new FileOutputStream(temp)));

			for (String line; (line = reader.readLine()) != null;) {
				line = HtmlEntities.decode(line);
				System.out.println(line);
				writer.println(line);
			}

		} catch (IOException e) {
			err = true;
			e.printStackTrace();
		} finally {
			try {
				reader.close();
				if (writer != null)
					writer.close();
			} catch (IOException e) {
				e.printStackTrace();
				return;
			}

		}

		if (!err && isNewXMLValid(temp)) {
			file.delete();
			temp.renameTo(file);
		}

	}

	protected boolean isNewXMLValid(File temp) {

		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setValidating(false);
		factory.setNamespaceAware(true);
		DocumentBuilder builder;

		try {
			builder = factory.newDocumentBuilder();
			InputSource is = new InputSource();
			is.setCharacterStream(new FileReader(temp));
			@SuppressWarnings("unused")
			Document document = builder.parse(is);
		} catch (SAXException e) {
			e.printStackTrace();
			Log.i(TAG, "reverting file to original");
			return false;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}

		return true;
	}


	public TagNode getRootNode(String url) {
		// TODO Auto-generated method stub
		return null;
	}

	public void cacheResult(boolean cacheIt) {
		this._cacheResult  = cacheIt;
	}

}
